package com.jysz.certificate.service.cm;

import java.io.File;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import com.jysz.certificate.persistence.dao.cm.CertificationCoreDao;
import com.jysz.certificate.persistence.dao.cm.ReleaseDao;
import com.jysz.certificate.persistence.enums.AttachmentType;
import com.jysz.certificate.persistence.enums.CertificationType;
import com.jysz.certificate.persistence.enums.PostType;
import com.jysz.certificate.persistence.enums.ReleaseState;
import com.jysz.certificate.persistence.enums.WorkflowOperateType;
import com.jysz.certificate.persistence.enums.WorkflowState;
import com.jysz.certificate.persistence.enums.WorkflowType;
import com.jysz.certificate.persistence.model.cm.Certification;
import com.jysz.certificate.persistence.model.cm.Release;
import com.jysz.certificate.persistence.model.system.Shop;
import com.jysz.certificate.persistence.model.system.User;
import com.jysz.certificate.persistence.model.workflow.Workflow;
import com.jysz.certificate.service.core.AttachmentService;
import com.jysz.certificate.service.system.ShopService;
import com.jysz.certificate.service.workflow.WorkflowService;
import com.jysz.certificate.utils.CommonUtil;
import com.jysz.certificate.utils.DateUtil;
import com.jysz.webcore.ssh.orm.hibernate.support.Page;
import com.jysz.webcore.ssh.service.EntityService;

/**
 * 释放单Service
 * @author xuxiaolong
 */
@Service
public class ReleaseService extends EntityService<Release, Long, ReleaseDao> {
	@Resource
	private ReleaseDao dao;
	@Resource
	private AttachmentService attService;
	@Resource
	private WorkflowService wfService;
	@Resource
	private ShopService shopService;

	@Resource
	private CertificationCoreDao cerDao;

	@Override
	public ReleaseDao getEntityDao() {
		return this.dao;
	}
	
	public Page<Release> findPage(Release search, int pageNo, int pageSize){
		Criteria criteria = dao.createCriteria();
		criteria.addOrder(Order.desc(Release.APPLYDATE));
		criteria.addOrder(Order.desc(Release.RELEASEDATE));
		if(search!=null){
			//金融机构
			if(search.getFinancial()!=null&&CommonUtil.isNotEmpty(search.getFinancial().getName()))
				criteria.createCriteria("financial").add(Restrictions.like("name", search.getFinancial().getName(),MatchMode.ANYWHERE));
			//释放单号
			if(CommonUtil.isNotEmpty(search.getReleaseNum()))
				criteria.add(Restrictions.like("releaseNum", search.getReleaseNum(), MatchMode.ANYWHERE));
			//申请单号
			if(CommonUtil.isNotEmpty(search.getApplyNum()))
				criteria.add(Restrictions.like("applyNum", search.getApplyNum(), MatchMode.ANYWHERE));
			//店名
			if(search.getShop()!=null&&CommonUtil.isNotEmpty(search.getShop().getShopName())){
				Criteria shopCriteria=criteria.createCriteria("shop").add(Restrictions.like("shopName", search.getShop().getShopName(),MatchMode.ANYWHERE));
				dao.addShopCriteria(shopCriteria,true,null);
			}else{
				dao.addShopCriteria(criteria,false,null);
			}
			//发起人
			if(search.getApplyUser()!=null&&CommonUtil.isNotEmpty(search.getApplyUser().getRealName()))
				criteria.createCriteria("applyUser").add(Restrictions.like("realName", search.getApplyUser().getRealName(),MatchMode.ANYWHERE));
			//状态
			if(search.getState()!=null)
				criteria.add(Restrictions.eq("state",search.getState()));
			//申请时间begin
			if(search.getApplyDate()!=null){
				criteria.add(Restrictions.ge("applyDate", DateUtil.getBeginDate(search.getApplyDate())));
			}
			//申请时间end
			if(search.getCreatedAt()!=null){
				criteria.add(Restrictions.le("applyDate", DateUtil.getEndDate(search.getCreatedAt())));
			}
			//释放时间begin
			if(search.getReleaseDate()!=null){
				criteria.add(Restrictions.ge("releaseDate", DateUtil.getBeginDate(search.getReleaseDate())));
			}
			//释放时间end
			if(search.getUpdatedAt()!=null){
				criteria.add(Restrictions.le("releaseDate", DateUtil.getEndDate(search.getUpdatedAt())));
			}
		}else{
			dao.addShopCriteria(criteria,false,null);
		}
		
		return this.findPage(criteria, pageNo, pageSize);
		
	}
	
	/**
	 * 仅保存
	 */
	public void saveOnly(User user,Release release,File file,String fileName){
		this.save(release);
		//上传附件
		if(file!=null)
			attService.addFile(user, AttachmentType.RELEASE, file, release.getId(),fileName);
		
	}
	
	/**
	 * 保存释放单并且提交新流程
	 * @throws Exception 
	 */
	public boolean saveAndSubmit(User currentUser,Release release,File file,String fileName,String msg){
		
		if(checkRelease(release)){//检查是否有已释放的合格证
			WorkflowState wfStatus=null;
			//店员提交状态为提交
			if(PostType.Shop.equals(currentUser.getPost())){
				release.setState(ReleaseState.SUBMITED);
				wfStatus=WorkflowState.SUBMITED;
				msg=msg==null?"":msg+"(驻店员提交释放单)";
			}else{
				release.setState(ReleaseState.FINISH);//监管科 直接为已完成
				wfStatus=WorkflowState.FINISH;
				this.release(release,currentUser);//直接释放所有合格证
				msg=msg==null?"":msg+"(监管科提交释放单,直接释放所有合格证)";
			}
			if(release.getId()==null)
				this.save(release);
			else
				this.merge(release);//保存释放单
			//--------流程---------
			Workflow wf=wfService.find(WorkflowType.RELEASE, release.getId());
			if(wf==null){
				//流程不存在,发起新流程
				wfService.addWorkflow(currentUser, release.getId(), wfStatus, WorkflowType.RELEASE, Release.class, msg);
			}else{
				// 流程已存在。更改流程状态即可。(可能是被退回的释放单)
				if(!StringUtils.isNotBlank(msg)){
					msg = "重新提交释放单流程";
				}
				wfService.audit(currentUser, wf,wfStatus,WorkflowOperateType.SUBMIT, msg);
			}
			//--------上传附件---------
			if(file!=null)
				attService.addFile(currentUser, AttachmentType.RELEASE, file, release.getId(), fileName);
			return true;
		}else{
//			throw new Exception("释放单提交失败,因为该释放单中包含已释放的合格证");
			return false;
		}
	}
	
	/**
	 * 释放单审核
	 * 退回只有全部退回;
	 * 通过传入的是通过的一部分的ids
	 * @param user
	 * @param id
	 * @param ids
	 * @param auditMsg
	 * @param releaseNum
	 * @param wfo
	 */
	public void audit(User user,Long id,Long []ids,String auditMsg,String releaseNum,WorkflowOperateType wfo){
		
		Release rs=this.find(id);
		//原单的释放单号
		rs.setReleaseNum(releaseNum);
		Workflow wf=wfService.find(WorkflowType.RELEASE,id);
		Set<Certification> cers=rs.getCertifications();
		
		//退回（只有全部退回）
		if(wfo.getIndex()==WorkflowOperateType.REFUSE.getIndex()){
			//释放单状态改为拒绝
			rs.setState(ReleaseState.REFUSED);
			//changeCertficaState(list,CertificationType.RELEASEAUDITPASSED);
			//流程状态改为拒绝，并记录操作
			wfService.audit(user, wf, WorkflowState.REFUSED, WorkflowOperateType.REFUSE,auditMsg);
		}
		//通过
		else{
			//不需要拆分
			if(cers==null||cers.size()==ids.length){
				//释放单状态改为已完成
				rs.setState(ReleaseState.FINISH);
				rs.setReleaseDate(new Date());//释放时间
				//释放所有合格证
				this.release(rs,user);
				//更改流程状态为通过,并记录操作
				wfService.audit(user, wf, WorkflowState.FINISH, WorkflowOperateType.PASS,auditMsg);
			}
			//部分通过，需要拆分
			else{
				Release newRs=new Release();
				Workflow newWf =new Workflow();
				BeanUtils.copyProperties(rs, newRs);//id,state,parent,split,depth
				
				newRs.setId(null);
				newRs.setReleaseNum(null);
				rs.setState(ReleaseState.FINISH);//部分通过  改为 已完成
				rs.setReleaseDate(new Date());//释放时间
				newRs.setState(ReleaseState.UN_FINISH_AUDIT);//新流程未结束审核
				newRs.setParent(rs);//给新释放单设置父单
				rs.setSplit(newRs);//给原释放单设置拆单
				newRs.setSplit(null);
				
				if(rs.getDepth()==1)
					newRs.setApplyNum(rs.getApplyNum()+"00001");
				else
					newRs.setApplyNum(buildSplitApplyNum(rs.getApplyNum()));
				newRs.setDepth(rs.getDepth()+1);//新单深度加1
				this.buildSplitObject(rs, newRs, cers, ids);//构建各自包含的合格证
				this.save(newRs);//新单级联保存
				this.release(rs,user);//原单直接释放
				this.save(rs);
				
				BeanUtils.copyProperties(wf, newWf);//id,state,objects,operates
				newWf.setId(null);
				newWf.setObjects(null);
				newWf.setOperates(null);
				Long []ary={newRs.getId()};
				newWf.setObjects(Workflow.buildWfObjects(newWf,ary));//新流程关联新单
				
				//将原流程改为通过，新流程为已提交
				wfService.audit(user, newWf, WorkflowState.SUBMITED, WorkflowOperateType.SUBMIT,"未完成审核");
				wf.setSplitWorkflow(newWf);
				wfService.audit(user, wf, WorkflowState.FINISH, WorkflowOperateType.PASS,auditMsg);
				
			}
		}
		
	}
	
	//检查释放单中是否包含已经释放的合格证
	public boolean checkRelease(Release release){
		for(Certification cf:release.getCertifications()){
			if(cf.getState().compareTo(CertificationType.RELEASEED)==0){
				return false;
			}
		}
		return true;
	}
	
	//整单释放
	public void release(Release release,User user){
		release(release.getCertifications(),release.getReleaseNum(), user,false);
	}
	
	public void release(Collection<Certification> cers,String releaseNum,User user,boolean delFromRelease){
		if(cers==null||user==null)
			return;
		for(Certification cf:cers){
			if(cf.getState().compareTo(CertificationType.RELEASEED)!=0){
				if(delFromRelease&&cf.getRelease()!=null){
					Release rs=cf.getRelease();
					Set<Certification> set=rs.getCertifications();
					if(set!=null&&set.size()==1){//如果释放单仅包含此一个合格证,删除。
						rs.setCertifications(null);
						this.save(rs);
						this.destory(rs);
						Workflow wf=wfService.find(WorkflowType.RELEASE, rs.getId());
						if(wf != null)
							wfService.destory(wf);
					}
					cf.setRelease(null);
				}
				cf.setState(CertificationType.RELEASEED);
				cf.setLeaveDate(new Date());//释放时间
				cf.setReleaseUser(user);//释放人
				cf.setReleaseNum(releaseNum);//释放单号
				cerDao.save(cf);
			}
		}
	}
	
	public void release(Collection<Certification> cers,User user,boolean delFromRelease){
		if(cers==null||user==null)
			return;
		for(Certification cf:cers){
			if(cf.getState().compareTo(CertificationType.RELEASEED)!=0){
				if(delFromRelease&&cf.getRelease()!=null){
					Release rs=cf.getRelease();
					
					Set<Certification> set=rs.getCertifications();
					if(set!=null&&set.size()==1){//如果释放单仅包含此一个合格证,删除。
						rs.setCertifications(null);
						this.save(rs);
						this.destory(rs);
						Workflow wf=wfService.find(WorkflowType.RELEASE, rs.getId());
						if(wf != null)
							wfService.destory(wf);
					}
					cf.setRelease(null);
					if(rs.getCertifications()!=null)
						rs.getCertifications().remove(cf);
				}
				cf.setState(CertificationType.RELEASEED);
				if(cf.getWarehouseDate()==null)//在途状态的入库日期为空，填充入库日期
					cf.setWarehouseDate(new Date());
				cf.setLeaveDate(new Date());//释放时间
				cf.setReleaseUser(user);//释放人
				cerDao.save(cf);
			}
		}
	}
	
	/**
	 * 审核拆单,构建新旧单各自包含的合格证
	 * @param passRs
	 * @param unpassRs
	 * @param all
	 * @param ids
	 */
	private void buildSplitObject(Release passRs,Release unpassRs,Set<Certification>all, Long[] ids) {
		Set<Certification> passSet=new HashSet<Certification>();
		Set<Certification> unpassSet=new HashSet<Certification>();
		Long tmpId = null;
		String ary = buildAryStr(ids);
		for (Certification cf : all) {
			tmpId = cf.getId();
			if (exist(ary, tmpId)) {
				cf.setRelease(passRs);
				passSet.add(cf);// 将通过的加入已通过集合checked
			}else{
				cf.setRelease(unpassRs);
				unpassSet.add(cf);// 将未通过的加入未通过集合unchecked
			}
		}
		passRs.setCertifications(passSet);
		unpassRs.setCertifications(unpassSet);
	}
 
	private boolean exist(String ids, Long tmp) {
		if (ids == null || tmp == null)
			return false;
		if (ids.indexOf("-" + tmp.toString()) != -1)
			return true;
		return false;

	}

	private String buildAryStr(Long[] ary) {
		StringBuilder sb = new StringBuilder();
		for (Long l : ary) {
			sb.append("-").append(l.toString());
		}
		return sb.toString();
	}
	
	/** 批量更改合格证状态*/
	private void changeCertficaState(List<Certification> list,CertificationType type){
		if(list!=null){
			for(Certification cf:list){
				cf.setLeaveDate(new Date());
				cf.setState(type);
			}
		}
	}
	
	
	/** 根据父申请单号获得拆分的新申请单号*/
	private String buildSplitApplyNum(String parent){
		String pre=parent.substring(0,parent.lastIndexOf("_")+1);
		String end=parent.substring(parent.lastIndexOf("_")+1, parent.length());
		int i=Integer.parseInt(end);
		i++;
		pre+=CommonUtil.getAutoNum(5, i);
		return pre;
	}
	
	/**
	 * 根据店 获得合格证释放单
	 * @param shops  销售店 ID
	 * @param releaseState 释放单状态
	 * @return 
	 */
	public Integer shopRelease(Set<Shop> shops, ReleaseState releaseState){
		Criteria criteria = this.cerDao.createCriteria();
		criteria.setProjection(Projections.rowCount());
		
		Criteria releaseCriteria = criteria.createCriteria("release");
		
		releaseCriteria.add(Restrictions.in("shop", shops));
		releaseCriteria.add(Restrictions.eq("state", releaseState));
		
		return ((Number)criteria.uniqueResult()).intValue();
	}
	
	//删除释放单
	public void destory(Long id){
		Release release = super.find(id);
		Set<Certification> l = release.getCertifications();
		if(l != null && l.size() > 0){
			for(Certification cer:l){
				cer.setRelease(null);
				cerDao.save(cer);
			}
		}
		Workflow wf = wfService.find(WorkflowType.RELEASE, id);
		if(wf != null){
			wfService.destory(wf);
		}
			
//		release.getList().clear();
//		super.save(release);
		Release parent = release.getParent();
		Release split = release.getSplit();
		if(parent == null && split != null){//只有子单,清空关系
			split.setParent(null);
			this.save(split);
		}else if(parent != null && split == null){//只有父单,清空关系
			parent.setSplit(null);
			Workflow parentWorkflow = wfService.find(WorkflowType.RELEASE, id);
			parentWorkflow.setSplitWorkflow(null);
			wfService.save(parentWorkflow);
			this.save(parent);
		}else if(parent != null && split != null){//都有,转移关系
			parent.setSplit(split);
			split.setParent(parent);
			this.save(parent);
			this.save(split);
		}
		attService.delFile(release.getId(), AttachmentType.RELEASE);
		super.destory(release.getId());
	}
}
